/*-------------------------------------------------------------------------
 *
 * nodes.h
 *	  标记节点的定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/nodes.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef NODES_H
#define NODES_H

/*
 * 每个节点的第一个字段是 NodeTag。每个创建的节点（使用 makeNode）
 * 将具有以下标签之一作为其第一个字段的值。
 *
 * 请注意，插入或删除节点类型会更改列表中后续其他节点类型的编号。
 * 在开发过程中没有问题，因为节点编号从未存储在磁盘上。
 * 但在已发布的分支中不要这样做，因为这将代表对扩展的 ABI 瓦解。
 */
typedef enum NodeTag
{
	T_Invalid = 0,

	/*
	 * 执行器节点的标签（execnodes.h）
	 */
	T_IndexInfo,
	T_ExprContext,
	T_ProjectionInfo,
	T_JunkFilter,
	T_OnConflictSetState,
	T_MergeActionState,
	T_ResultRelInfo,
	T_EState,
	T_TupleTableSlot,

	/*
	 * 计划节点的标签（plannodes.h）
	 */
	T_Plan,
	T_Result,
	T_ProjectSet,
	T_ModifyTable,
	T_Append,
	T_MergeAppend,
	T_RecursiveUnion,
	T_BitmapAnd,
	T_BitmapOr,
	T_Scan,
	T_SeqScan,
	T_SampleScan,
	T_IndexScan,
	T_IndexOnlyScan,
	T_BitmapIndexScan,
	T_BitmapHeapScan,
	T_TidScan,
	T_TidRangeScan,
	T_SubqueryScan,
	T_FunctionScan,
	T_ValuesScan,
	T_TableFuncScan,
	T_CteScan,
	T_NamedTuplestoreScan,
	T_WorkTableScan,
	T_ForeignScan,
	T_CustomScan,
	T_Join,
	T_NestLoop,
	T_MergeJoin,
	T_HashJoin,
	T_Material,
	T_Memoize,
	T_Sort,
	T_IncrementalSort,
	T_Group,
	T_Agg,
	T_WindowAgg,
	T_Unique,
	T_Gather,
	T_GatherMerge,
	T_Hash,
	T_SetOp,
	T_LockRows,
	T_Limit,
	/* 这些不是计划的子类： */
	T_NestLoopParam,
	T_PlanRowMark,
	T_PartitionPruneInfo,
	T_PartitionedRelPruneInfo,
	T_PartitionPruneStepOp,
	T_PartitionPruneStepCombine,
	T_PlanInvalItem,

	/*
	 * 计划状态节点的标签（execnodes.h）
	 *
	 * 这些应与计划节点类型一一对应。
	 */
	T_PlanState,
	T_ResultState,
	T_ProjectSetState,
	T_ModifyTableState,
	T_AppendState,
	T_MergeAppendState,
	T_RecursiveUnionState,
	T_BitmapAndState,
	T_BitmapOrState,
	T_ScanState,
	T_SeqScanState,
	T_SampleScanState,
	T_IndexScanState,
	T_IndexOnlyScanState,
	T_BitmapIndexScanState,
	T_BitmapHeapScanState,
	T_TidScanState,
	T_TidRangeScanState,
	T_SubqueryScanState,
	T_FunctionScanState,
	T_TableFuncScanState,
	T_ValuesScanState,
	T_CteScanState,
	T_NamedTuplestoreScanState,
	T_WorkTableScanState,
	T_ForeignScanState,
	T_CustomScanState,
	T_JoinState,
	T_NestLoopState,
	T_MergeJoinState,
	T_HashJoinState,
	T_MaterialState,
	T_MemoizeState,
	T_SortState,
	T_IncrementalSortState,
	T_GroupState,
	T_AggState,
	T_WindowAggState,
	T_UniqueState,
	T_GatherState,
	T_GatherMergeState,
	T_HashState,
	T_SetOpState,
	T_LockRowsState,
	T_LimitState,

	/*
	 * 原生节点的标签（primnodes.h）
	 */
	T_Alias,
	T_RangeVar,
	T_TableFunc,
	T_Var,
	T_Const,
	T_Param,
	T_Aggref,
	T_GroupingFunc,
	T_WindowFunc,
	T_SubscriptingRef,
	T_FuncExpr,
	T_NamedArgExpr,
	T_OpExpr,
	T_DistinctExpr,
	T_NullIfExpr,
	T_ScalarArrayOpExpr,
	T_BoolExpr,
	T_SubLink,
	T_SubPlan,
	T_AlternativeSubPlan,
	T_FieldSelect,
	T_FieldStore,
	T_RelabelType,
	T_CoerceViaIO,
	T_ArrayCoerceExpr,
	T_ConvertRowtypeExpr,
	T_CollateExpr,
	T_CaseExpr,
	T_CaseWhen,
	T_CaseTestExpr,
	T_ArrayExpr,
	T_RowExpr,
	T_RowCompareExpr,
	T_CoalesceExpr,
	T_MinMaxExpr,
	T_SQLValueFunction,
	T_XmlExpr,
	T_NullTest,
	T_BooleanTest,
	T_CoerceToDomain,
	T_CoerceToDomainValue,
	T_SetToDefault,
	T_CurrentOfExpr,
	T_NextValueExpr,
	T_InferenceElem,
	T_TargetEntry,
	T_RangeTblRef,
	T_JoinExpr,
	T_FromExpr,
	T_OnConflictExpr,
	T_IntoClause,

	/*
	 * 表达式状态节点的标签（execnodes.h）
	 *
	 * ExprState 表示整个表达式树的评估状态。
	 * 大多数基于 Expr 的计划节点没有对应的表达式状态
	 * 节点，它们完全由 execExpr* 处理 - 但是有时状态
	 * 需要与执行器的其他部分共享，例如
	 * SubPlanState，nodeSubplan.c 必须修改。
	 */
	T_ExprState,
	T_WindowFuncExprState,
	T_SetExprState,
	T_SubPlanState,
	T_DomainConstraintState,

	/*
	 * 规划者节点的标签（pathnodes.h）
	 */
	T_PlannerInfo,
	T_PlannerGlobal,
	T_RelOptInfo,
	T_IndexOptInfo,
	T_ForeignKeyOptInfo,
	T_ParamPathInfo,
	T_Path,
	T_IndexPath,
	T_BitmapHeapPath,
	T_BitmapAndPath,
	T_BitmapOrPath,
	T_TidPath,
	T_TidRangePath,
	T_SubqueryScanPath,
	T_ForeignPath,
	T_CustomPath,
	T_NestPath,
	T_MergePath,
	T_HashPath,
	T_AppendPath,
	T_MergeAppendPath,
	T_GroupResultPath,
	T_MaterialPath,
	T_MemoizePath,
	T_UniquePath,
	T_GatherPath,
	T_GatherMergePath,
	T_ProjectionPath,
	T_ProjectSetPath,
	T_SortPath,
	T_IncrementalSortPath,
	T_GroupPath,
	T_UpperUniquePath,
	T_AggPath,
	T_GroupingSetsPath,
	T_MinMaxAggPath,
	T_WindowAggPath,
	T_SetOpPath,
	T_RecursiveUnionPath,
	T_LockRowsPath,
	T_ModifyTablePath,
	T_LimitPath,
	/* 这些不是 Path 的子类： */
	T_EquivalenceClass,
	T_EquivalenceMember,
	T_PathKey,
	T_PathKeyInfo,
	T_PathTarget,
	T_RestrictInfo,
	T_IndexClause,
	T_PlaceHolderVar,
	T_SpecialJoinInfo,
	T_AppendRelInfo,
	T_RowIdentityVarInfo,
	T_PlaceHolderInfo,
	T_MinMaxAggInfo,
	T_PlannerParamItem,
	T_RollupData,
	T_GroupingSetData,
	T_StatisticExtInfo,
	T_MergeAction,

	/*
	 * 内存节点的标签（memnodes.h）
	 */
	T_AllocSetContext,
	T_SlabContext,
	T_GenerationContext,

	/*
	 * 值节点的标签（value.h）
	 */
	T_Integer,
	T_Float,
	T_Boolean,
	T_String,
	T_BitString,

	/*
	 * 列表节点的标签（pg_list.h）
	 */
	T_List,
	T_IntList,
	T_OidList,

	/*
	 * 可扩展节点的标签（extensible.h）
	 */
	T_ExtensibleNode,

	/*
	 * 语句节点的标签（主要在 parsenodes.h 中）
	 */
	T_RawStmt,
	T_Query,
	T_PlannedStmt,
	T_InsertStmt,
	T_DeleteStmt,
	T_UpdateStmt,
	T_MergeStmt,
	T_SelectStmt,
	T_ReturnStmt,
	T_PLAssignStmt,
	T_AlterTableStmt,
	T_AlterTableCmd,
	T_AlterDomainStmt,
	T_SetOperationStmt,
	T_GrantStmt,
	T_GrantRoleStmt,
	T_AlterDefaultPrivilegesStmt,
	T_ClosePortalStmt,
	T_ClusterStmt,
	T_CopyStmt,
	T_CreateStmt,
	T_DefineStmt,
	T_DropStmt,
	T_TruncateStmt,
	T_CommentStmt,
	T_FetchStmt,
	T_IndexStmt,
	T_CreateFunctionStmt,
	T_AlterFunctionStmt,
	T_DoStmt,
	T_RenameStmt,
	T_RuleStmt,
	T_NotifyStmt,
	T_ListenStmt,
	T_UnlistenStmt,
	T_TransactionStmt,
	T_ViewStmt,
	T_LoadStmt,
	T_CreateDomainStmt,
	T_CreatedbStmt,
	T_DropdbStmt,
	T_VacuumStmt,
	T_ExplainStmt,
	T_CreateTableAsStmt,
	T_CreateSeqStmt,
	T_AlterSeqStmt,
	T_VariableSetStmt,
	T_VariableShowStmt,
	T_DiscardStmt,
	T_CreateTrigStmt,
	T_CreatePLangStmt,
	T_CreateRoleStmt,
	T_AlterRoleStmt,
	T_DropRoleStmt,
	T_LockStmt,
	T_ConstraintsSetStmt,
	T_ReindexStmt,
	T_CheckPointStmt,
	T_CreateSchemaStmt,
	T_AlterDatabaseStmt,
	T_AlterDatabaseRefreshCollStmt,
	T_AlterDatabaseSetStmt,
	T_AlterRoleSetStmt,
	T_CreateConversionStmt,
	T_CreateCastStmt,
	T_CreateOpClassStmt,
	T_CreateOpFamilyStmt,
	T_AlterOpFamilyStmt,
	T_PrepareStmt,
	T_ExecuteStmt,
	T_DeallocateStmt,
	T_DeclareCursorStmt,
	T_CreateTableSpaceStmt,
	T_DropTableSpaceStmt,
	T_AlterObjectDependsStmt,
	T_AlterObjectSchemaStmt,
	T_AlterOwnerStmt,
	T_AlterOperatorStmt,
	T_AlterTypeStmt,
	T_DropOwnedStmt,
	T_ReassignOwnedStmt,
	T_CompositeTypeStmt,
	T_CreateEnumStmt,
	T_CreateRangeStmt,
	T_AlterEnumStmt,
	T_AlterTSDictionaryStmt,
	T_AlterTSConfigurationStmt,
	T_CreateFdwStmt,
	T_AlterFdwStmt,
	T_CreateForeignServerStmt,
	T_AlterForeignServerStmt,
	T_CreateUserMappingStmt,
	T_AlterUserMappingStmt,
	T_DropUserMappingStmt,
	T_AlterTableSpaceOptionsStmt,
	T_AlterTableMoveAllStmt,
	T_SecLabelStmt,
	T_CreateForeignTableStmt,
	T_ImportForeignSchemaStmt,
	T_CreateExtensionStmt,
	T_AlterExtensionStmt,
	T_AlterExtensionContentsStmt,
	T_CreateEventTrigStmt,
	T_AlterEventTrigStmt,
	T_RefreshMatViewStmt,
	T_ReplicaIdentityStmt,
	T_AlterSystemStmt,
	T_CreatePolicyStmt,
	T_AlterPolicyStmt,
	T_CreateTransformStmt,
	T_CreateAmStmt,
	T_CreatePublicationStmt,
	T_AlterPublicationStmt,
	T_CreateSubscriptionStmt,
	T_AlterSubscriptionStmt,
	T_DropSubscriptionStmt,
	T_CreateStatsStmt,
	T_AlterCollationStmt,
	T_CallStmt,
	T_AlterStatsStmt,

	/*
	 * 解析树节点的标签（parsenodes.h）
	 */
	T_A_Expr,
	T_ColumnRef,
	T_ParamRef,
	T_A_Const,
	T_FuncCall,
	T_A_Star,
	T_A_Indices,
	T_A_Indirection,
	T_A_ArrayExpr,
	T_ResTarget,
	T_MultiAssignRef,
	T_TypeCast,
	T_CollateClause,
	T_SortBy,
	T_WindowDef,
	T_RangeSubselect,
	T_RangeFunction,
	T_RangeTableSample,
	T_RangeTableFunc,
	T_RangeTableFuncCol,
	T_TypeName,
	T_ColumnDef,
	T_IndexElem,
	T_StatsElem,
	T_Constraint,
	T_DefElem,
	T_RangeTblEntry,
	T_RangeTblFunction,
	T_TableSampleClause,
	T_WithCheckOption,
	T_SortGroupClause,
	T_GroupingSet,
	T_WindowClause,
	T_ObjectWithArgs,
	T_AccessPriv,
	T_CreateOpClassItem,
	T_TableLikeClause,
	T_FunctionParameter,
	T_LockingClause,
	T_RowMarkClause,
	T_XmlSerialize,
	T_WithClause,
	T_InferClause,
	T_OnConflictClause,
	T_CTESearchClause,
	T_CTECycleClause,
	T_CommonTableExpr,
	T_MergeWhenClause,
	T_RoleSpec,
	T_TriggerTransition,
	T_PartitionElem,
	T_PartitionSpec,
	T_PartitionBoundSpec,
	T_PartitionRangeDatum,
	T_PartitionCmd,
	T_VacuumRelation,
	T_PublicationObjSpec,
	T_PublicationTable,

	/*
	 * 复制语法解析节点的标签（replnodes.h）
	 */
	T_IdentifySystemCmd,
	T_BaseBackupCmd,
	T_CreateReplicationSlotCmd,
	T_DropReplicationSlotCmd,
	T_ReadReplicationSlotCmd,
	T_StartReplicationCmd,
	T_TimeLineHistoryCmd,

	/*
	 * 随机其他内容的标签
	 *
	 * 这些是非解析/计划/执行节点树
	 * 结构的一部分，但我们仍然给它们 NodeTags 以便识别
	 * （通常是因为它们涉及到 API，我们希望
	 * 通过同一个指针传递多种对象类型）。
	 */
	T_TriggerData,				/* in commands/trigger.h */
	T_EventTriggerData,			/* 在 commands/event_trigger.h 中 */
	T_ReturnSetInfo,			/* 在 nodes/execnodes.h 中 */
	T_WindowObjectData,			/* private in nodeWindowAgg.c */
	T_TIDBitmap,				/* 在 nodes/tidbitmap.h 中 */
	T_InlineCodeBlock,			/* 在 nodes/parsenodes.h 中 */
	T_FdwRoutine,				/* 在 foreign/fdwapi.h 中 */
	T_IndexAmRoutine,			/* 在 access/amapi.h 中 */
	T_TableAmRoutine,			/* 在 access/tableam.h 中 */
	T_TsmRoutine,				/* 在 access/tsmapi.h 中 */
	T_ForeignKeyCacheInfo,		/* 在 utils/rel.h 中 */
	T_CallContext,				/* 在 nodes/parsenodes.h 中 */
	T_SupportRequestSimplify,	/* 在nodes/supportnodes.h中 */
	T_SupportRequestSelectivity,	/* 在nodes/supportnodes.h中 */
	T_SupportRequestCost,		/* 在nodes/supportnodes.h中 */
	T_SupportRequestRows,		/* 在nodes/supportnodes.h中 */
	T_SupportRequestIndexCondition, /* 在nodes/supportnodes.h中 */
	T_SupportRequestWFuncMonotonic	/* 在nodes/supportnodes.h中 */
} NodeTag;

/*
 * 任何类型节点的第一个字段保证是 NodeTag。
 * 因此，可以通过将其强制转换为 Node 来获取任何节点的类型。声明
 * 一个变量为 Node *（而不是 void *）也可以有助于
 * 调试。
 */
typedef struct Node
{
	NodeTag		type;
} Node;

#define nodeTag(nodeptr)		(((const Node*)(nodeptr))->type)

/*
 * newNode -
 *	  创建指定大小的新节点，并用
 *	  指定的标签标记该节点。
 *
 * !警告!: 避免直接使用 newNode。你应该使用
 *	  宏 makeNode。例如，要创建一个 Query 节点，请使用 makeNode(Query)
 *
 * 注意：大小参数应该始终是编译时常量，因此
 * 多个评估的明显风险在实际中并不重要。
 */
#ifdef __GNUC__

/* 在 GCC 下，我们可以在表达式中使用复合语句 */
#define newNode(size, tag) \
({	Node   *_result; \
	AssertMacro((size) >= sizeof(Node));		/* 至少需要标签 */ \
	_result = (Node *) palloc0fast(size); \
	_result->type = (tag); \
	_result; \
})
#else

/*
 *	没有办法取消引用 palloc' 的指针以赋值
 *	标签，并同时返回指针本身，因此我们需要一个持有变量。
 *	幸运的是，这个宏不是递归的，所以我们只需为此目的定义
 *	一个全局变量。
 */
extern PGDLLIMPORT Node *newNodeMacroHolder;

#define newNode(size, tag) \
( \
	AssertMacro((size) >= sizeof(Node)),		/* 至少需要标签 */ \
	newNodeMacroHolder = (Node *) palloc0fast(size), \
	newNodeMacroHolder->type = (tag), \
	newNodeMacroHolder \
)
#endif							/* __GNUC__ */


#define makeNode(_type_)		((_type_ *) newNode(sizeof(_type_),T_##_type_))
#define NodeSetTag(nodeptr,t)	(((Node*)(nodeptr))->type = (t))

#define IsA(nodeptr,_type_)		(nodeTag(nodeptr) == T_##_type_)

/*
 * castNode(type, ptr) 将 ptr 强制转换为 "type *"，并且如果启用了断言，
 * 将验证节点具有适当的类型（使用其 nodeTag()）。
 *
 * 在启用断言时使用内联函数，以避免对 ptr 参数的多个
 * 评估（例如，可能是函数调用）。
 */
#ifdef USE_ASSERT_CHECKING
static inline Node *
castNodeImpl(NodeTag type, void *ptr)
{
	Assert(ptr == NULL || nodeTag(ptr) == type);
	return (Node *) ptr;
}
#define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(T_##_type_, nodeptr))
#else
#define castNode(_type_, nodeptr) ((_type_ *) (nodeptr))
#endif							/* USE_ASSERT_CHECKING */


/* ----------------------------------------------------------------
 *					  extern 声明跟随
 * ----------------------------------------------------------------
 */

/*
 * nodes/{outfuncs.c,print.c}
 */
struct Bitmapset;				/* 不要在这里包含 bitmapset.h */
struct StringInfoData;			/* 不要在这里包含 stringinfo.h */

extern void outNode(struct StringInfoData *str, const void *obj);
extern void outToken(struct StringInfoData *str, const char *s);
extern void outBitmapset(struct StringInfoData *str,
						 const struct Bitmapset *bms);
extern void outDatum(struct StringInfoData *str, uintptr_t value,
					 int typlen, bool typbyval);
extern char *nodeToString(const void *obj);
extern char *bmsToString(const struct Bitmapset *bms);

/*
 * nodes/{readfuncs.c,read.c}
 */
extern void *stringToNode(const char *str);
#ifdef WRITE_READ_PARSE_PLAN_TREES
extern void *stringToNodeWithLocations(const char *str);
#endif
extern struct Bitmapset *readBitmapset(void);
extern uintptr_t readDatum(bool typbyval);
extern bool *readBoolCols(int numCols);
extern int *readIntCols(int numCols);
extern Oid *readOidCols(int numCols);
extern int16 *readAttrNumberCols(int numCols);

/*
 * nodes/copyfuncs.c
 */
extern void *copyObjectImpl(const void *obj);

/* 如果编译器支持，将结果强制转换回参数类型 */
#ifdef HAVE_TYPEOF
#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj))
#else
#define copyObject(obj) copyObjectImpl(obj)
#endif

/*
 * nodes/equalfuncs.c
 */
extern bool equal(const void *a, const void *b);


/*
 * 用于识别限制选择性和计划成本的 typedef。
 * 这些只是普通的 "double"，但将变量声明为 Selectivity
 * 或 Cost 使意图更加明显。
 *
 * 这些可以放入 plannodes.h 或其他地方，但许多文件
 * 依赖于它们...
 */
typedef double Selectivity;		/* 限制将通过的元组的比例 */
typedef double Cost;			/* 执行成本（以页访问单位） */
typedef double Cardinality;		/* （估计的）行数或其他整数
								 * 计数 */


/*
 * CmdType -
 *	  表示 Query 或 PlannedStmt 的操作类型的枚举
 *
 * 这在 parsenodes.h 和 plannodes.h 中都是需要的，所以放在这里...
 */
typedef enum CmdType
{
	CMD_UNKNOWN,
	CMD_SELECT,					/* 选择语句 */
	CMD_UPDATE,					/* 更新语句 */
	CMD_INSERT,					/* 插入语句 */
	CMD_DELETE,					/* 删除语句 */
	CMD_MERGE,					/* 合并语句 */
	CMD_UTILITY,				/* 像创建、销毁、复制、清理等命令 */
	CMD_NOTHING					/* 虚拟命令用于代替没有规则的条件 */
} CmdType;


/*
 * JoinType -
 *	  关系连接类型的枚举
 *
 * JoinType 确定使用匹配条件连接两个关系的确切语义。例如，它告诉我们如何处理在另一个关系中没有匹配的元组。
 *
 * 这在 parsenodes.h 和 plannodes.h 中都是需要的，所以放在这里...
 */
typedef enum JoinType
{
	/*
	 * 根据 SQL JOIN 语法的标准连接类型。只有这些代码可以出现在解析器输出中（例如，JoinExpr 节点）。
	 */
	JOIN_INNER,					/* 仅匹配的元组对 */
	JOIN_LEFT,					/* 对 + 没有匹配的左侧元组 */
	JOIN_FULL,					/* 对 + 没有匹配的左侧 + 没有匹配的右侧 */
	JOIN_RIGHT,					/* 对 + 没有匹配的右侧元组 */

	/*
	 * 半连接和反半连接（如在关系理论中定义）并不出现在 SQL JOIN 语法中，但有标准习惯用法来表示它们（例如，使用 EXISTS）。规划器识别这些情况并将其转换为连接。因此，规划器和执行器必须支持这些代码。注意：在 JOIN_SEMI 输出中，未指定连接到哪个匹配的右侧行。在 JOIN_ANTI 输出中，保证行为 null 扩展。
	 */
	JOIN_SEMI,					/* 每个有匹配的左侧行的一份副本 */
	JOIN_ANTI,					/* 每个没有匹配的左侧行的一份副本 */

	/*
	 * 这些代码在规划器内部使用，但执行器不支持这些（实际上，大多数规划器也不支持）。
	 */
	JOIN_UNIQUE_OUTER,			/* 左侧路径必须唯一 */
	JOIN_UNIQUE_INNER			/* 右侧路径必须唯一 */

	/*
	 * 我们可能在将来需要额外的连接类型。
	 */
} JoinType;

/*
 * 外连接是那些被压缩下来的条件必须与连接自身的条件表现不同的连接。实际上，除了 INNER 和 SEMI 连接之外的所有连接都是如此。然而，此宏也必须排除 JOIN_UNIQUE 符号，因为这些是最终将成为 INNER 连接的临时代理。
 *
 * 注意：半连接是混合情况，但我们选择将它们视为不是外连接。这是可以接受的，主要是因为 SQL 语法使得不可能有压缩下来的条件引用半连接的内侧关系；因此，没有强烈的需求区分连接条件和压缩下来的条件。这是方便的，因为在几乎所有情况下，附加到半连接的条件可以与内部连接条件相同对待。
 */
#define IS_OUTER_JOIN(jointype) \
	(((1 << (jointype)) & \
	  ((1 << JOIN_LEFT) | \
	   (1 << JOIN_FULL) | \
	   (1 << JOIN_RIGHT) | \
	   (1 << JOIN_ANTI))) != 0)

/*
 * AggStrategy -
 *	  Agg 计划节点的总体执行策略
 *
 * 这在 pathnodes.h 和 plannodes.h 中都是需要的，所以放在这里...
 */
typedef enum AggStrategy
{
	AGG_PLAIN,					/* 所有输入行的简单聚合 */
	AGG_SORTED,					/* 分组聚合，输入必须排序 */
	AGG_HASHED,					/* 分组聚合，使用内部哈希表 */
	AGG_MIXED					/* 分组聚合，同时使用哈希和排序 */
} AggStrategy;

/*
 * AggSplit -
 *	  Agg 计划节点的分离（部分聚合）模式
 *
 * 这在 pathnodes.h 和 plannodes.h 中都是需要的，所以放在这里...
 */

/* nodeAgg.c 支持的原始选项： */
#define AGGSPLITOP_COMBINE		0x01	/* 用 combinefn 替代 transfn */
#define AGGSPLITOP_SKIPFINAL	0x02	/* 跳过 finalfn，按原样返回状态 */
#define AGGSPLITOP_SERIALIZE	0x04	/* 将 serialfn 应用到输出 */
#define AGGSPLITOP_DESERIALIZE	0x08	/* 应用 deserialfn 到输入 */

/* 支持的操作模式（即，这些选项的有用组合）： */
typedef enum AggSplit
{
	/* 基本的，非拆分聚合： */
	AGGSPLIT_SIMPLE = 0,
	/* 部分聚合的初始阶段，带有序列化： */
	AGGSPLIT_INITIAL_SERIAL = AGGSPLITOP_SKIPFINAL | AGGSPLITOP_SERIALIZE,
	/* 部分聚合的最终阶段，带有反序列化： */
	AGGSPLIT_FINAL_DESERIAL = AGGSPLITOP_COMBINE | AGGSPLITOP_DESERIALIZE
} AggSplit;

/* 测试 AggSplit 值是否选择每个原始选项： */
#define DO_AGGSPLIT_COMBINE(as)		(((as) & AGGSPLITOP_COMBINE) != 0)
#define DO_AGGSPLIT_SKIPFINAL(as)	(((as) & AGGSPLITOP_SKIPFINAL) != 0)
#define DO_AGGSPLIT_SERIALIZE(as)	(((as) & AGGSPLITOP_SERIALIZE) != 0)
#define DO_AGGSPLIT_DESERIALIZE(as) (((as) & AGGSPLITOP_DESERIALIZE) != 0)

/*
 * SetOpCmd 和 SetOpStrategy -
 *	  SetOp 计划节点的整体语义和执行策略
 *
 * 这在 pathnodes.h 和 plannodes.h 中都是必需的，所以放在这里...
 */
typedef enum SetOpCmd
{
	SETOPCMD_INTERSECT,
	SETOPCMD_INTERSECT_ALL,
	SETOPCMD_EXCEPT,
	SETOPCMD_EXCEPT_ALL
} SetOpCmd;

typedef enum SetOpStrategy
{
	SETOP_SORTED,				/* 输入必须排序 */
	SETOP_HASHED				/* 使用内部哈希表 */
} SetOpStrategy;

/*
 * OnConflictAction -
 *	  "ON CONFLICT" 子句类型的查询
 *
 * 这在 parsenodes.h 和 plannodes.h 中都是必需的，所以放在这里...
 */
typedef enum OnConflictAction
{
	ONCONFLICT_NONE,			/* 没有 "ON CONFLICT" 子句 */
	ONCONFLICT_NOTHING,			/* ON CONFLICT ... DO NOTHING */
	ONCONFLICT_UPDATE			/* ON CONFLICT ... DO UPDATE */
} OnConflictAction;

/*
 * LimitOption -
 *	查询的 LIMIT 选项
 *
 * 这在 parsenodes.h 和 plannodes.h 中都是必需的，所以放在这里...
 */
typedef enum LimitOption
{
	LIMIT_OPTION_COUNT,			/* FETCH FIRST... ONLY */
	LIMIT_OPTION_WITH_TIES,		/* FETCH FIRST... WITH TIES */
	LIMIT_OPTION_DEFAULT,		/* 没有限制存在 */
} LimitOption;

#endif							/* NODES_H */
